home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / bootpd.c < prev    next >
C/C++ Source or Header  |  1991-05-31  |  12KB  |  511 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.  
  13.  
  14. /*
  15.  * BOOTP (bootstrap protocol) server daemon.
  16.  *
  17.  */
  18.  
  19.  
  20. #include <stdio.h>
  21. #include <sys\types.h>
  22. #include <sys\stat.h>
  23. #include <ctype.h>
  24. #include <time.h>
  25.  
  26. #include "global.h"
  27. #include "config.h"
  28. #include "bootp.h"
  29. #include "cmdparse.h"
  30. #include "iface.h"
  31. #include "mbuf.h"
  32. #include "proc.h"
  33. #include "socket.h"
  34. #include "bootpd.h"
  35. #include "udp.h"
  36. #include "ip.h"
  37. #include "arp.h"
  38. #include "netuser.h"
  39.  
  40. void bootpd __ARGS((struct iface *iface, struct udp_cb *sock, int cnt)); 
  41.  
  42. struct udp_cb *Bootpd_cb = NULLUDP;
  43.  
  44. char homedir[64] = "";              /* bootfile homedirectory */
  45. char defaultboot[64] = "";          /* default file to boot */
  46.  
  47. struct host hosts[MHOSTS+1];
  48. int Nhosts = 0;       /* current number of hosts */
  49.  
  50. int32 bp_DefaultDomainNS[BP_MAXDNS] =  {0};
  51.  
  52. struct bootpd_stat Bootpd_stat;
  53.  
  54. char *ArpNames[] = {
  55.     "Netrom",
  56.     "Ethernet",
  57.     "AX25",
  58.     "Pronet",
  59.     "Chaos",
  60.     "IEEE 802",
  61.     "ArcNet",
  62.     "AppleTalk" 
  63. };
  64.  
  65.  
  66. /* Routine declarations */
  67. static int bootpd_recv __ARGS((struct udp_cb *sock,struct bootp *bootp));
  68. static void sendreply __ARGS((struct bootp *bp,struct iface *iface));
  69. static void vend_fill __ARGS((char *vend,struct iface *iface,struct host *hp));
  70. static void vend_print __ARGS((char *vend));
  71. static void bootpd_request __ARGS((struct bootp *rq,struct iface *iface));
  72.  
  73. /* The bootp server. */
  74. void 
  75. bootpd(iface,sock,cnt)
  76. struct iface *iface;
  77. struct udp_cb *sock;
  78. int cnt;
  79. {
  80.     struct bootp bp_packet;
  81.  
  82.     while(bootpd_recv(sock, &bp_packet) != -1) {
  83.  
  84.                if(readtab() == -1) /* maybe re-read bootptab */
  85.             return;
  86.  
  87.         switch(uchar(bp_packet.op)) {
  88.             case BOOTREQUEST:
  89.             bootpd_request(&bp_packet, iface); 
  90.             break;
  91.         case BOOTREPLY: 
  92.             /* Replies are not forwarded, left to the gateway */ 
  93.             break;
  94.         }
  95.  
  96.     }
  97.  
  98. }
  99.  
  100. /* A packet has been received, read it into a bootp structure. */
  101. static int
  102. bootpd_recv(sock, bootp)
  103. struct udp_cb *sock;
  104. struct bootp *bootp;
  105. {
  106.     struct socket fsock;
  107.     struct mbuf *bp;
  108.     int len;
  109.  
  110.     /* increment the rcvd cnt */
  111.     Bootpd_stat.rcvd++;
  112.  
  113.     /* receive the packet */
  114.     len = recv_udp(sock,&fsock,&bp);
  115.     if(len == -1)
  116.         return -1;
  117.  
  118.  
  119.     /* check length of packet */
  120.     if(len < sizeof(struct bootp)) {
  121.         Bootpd_stat.bad_size++;
  122.         bootp->op = 0;
  123.         free_p(bp);
  124.         return -1;
  125.     }
  126.         
  127.     /* parse the packet */
  128.     pullup (&bp, (char *)bootp, sizeof (struct bootp));
  129.     free_p(bp);    
  130.  
  131.     if(bootp->op != BOOTREPLY  &&  bootp->op != BOOTREQUEST) {
  132.         Bootpd_stat.bad_op++;
  133.         bootp->op = 0;
  134.         return -1;
  135.     }
  136.  
  137.     bootp->ciaddr.s_addr = (unsigned long) get32 ((char *)&(bootp->ciaddr));
  138.     bootp->giaddr.s_addr = (unsigned long) get32 ((char *)&(bootp->giaddr));
  139.     return 0;
  140. };
  141.  
  142.  
  143. /*
  144.  * Process BOOTREQUEST packet.
  145.  *
  146.  * (Note, this version of the bootp.c server never forwards 
  147.  * the request to another server.  In our environment the 
  148.  * stand-alone gateways perform that function.)
  149.  *
  150.  * (Also this version does not interpret the hostname field of
  151.  * the request packet;  it COULD do a name->address lookup and
  152.  * forward the request there.)
  153.  */
  154.  
  155. static void
  156. bootpd_request (rq, iface)
  157. struct bootp *rq;
  158. struct iface *iface;
  159. {
  160.  
  161.     struct bootp *rp;
  162.     char path[64], file[64];
  163.     struct host *hp;
  164.     int n;
  165.     time_t tloc;
  166.     int32 ipaddr;
  167.     struct arp_type *at;
  168.  
  169.     time(&tloc);
  170.     bp_log ("\nBootpd request packet received %s", ctime(&tloc));
  171.     /* Forwarding not done here. */
  172.     if(rq->giaddr.s_addr)  {
  173.         bp_log ("     Dropped, giaddr specifies to be forwarded;\n");
  174.         return;
  175.     }
  176.  
  177.     /* Is a specific host requested? */
  178.     if((strlen(rq->sname) != 0) && (strcmp (Hostname, rq->sname) != 0)) {
  179.         bp_log ("     Dropped, sname specifies server '%s'\n", rq->sname);  
  180.         return;
  181.     }
  182.  
  183.     /* allocate the reply */
  184.     rp = (struct bootp *) calloc (1, sizeof (struct bootp));
  185.  
  186.     /* copy for construction */
  187.     memcpy (rp, rq, sizeof (struct bootp) - sizeof (rp->vend));
  188.  
  189.     rp->op = BOOTREPLY;
  190.  
  191.     hp = NULLHOST;
  192.  
  193.  
  194.     /* If the client doesn't know it's ip address, find one. */
  195.     if(rq->ciaddr.s_addr == 0) { 
  196.  
  197.         /*
  198.          * client doesn't know his IP address, 
  199.          * search by hardware address.
  200.          */
  201.         at = &Arp_type[rq->htype];
  202.         bp_log ("     Resolved by %s addr %s\n", ArpNames[rq->htype], 
  203.             (*at->format)(bp_ascii, rq->chaddr));
  204.  
  205.         for(hp = &hosts[0], n = 0 ; n < Nhosts ; n++,hp++)
  206.             if((rq->htype == hp->htype)
  207.                && (strncmp(rq->chaddr, hp->haddr, rq->hlen) == 0))
  208.                 break;
  209.  
  210.         /* If the client wasn't found, assign an IP address */
  211.         if(n == Nhosts) {
  212.  
  213.             hp = NULLHOST;
  214.             if(da_assign(iface, rq->chaddr, &ipaddr) != 0) {
  215.                 free (rp);
  216.                 bp_log ("     No dynamic addresses available.\n");
  217.                 return;
  218.             } else {        
  219.                 put32 ((char *) &(rp->yiaddr), ipaddr);
  220.                 bp_log ("     Dynamic address assigned: %s\n", 
  221.                     inet_ntoa (ipaddr));
  222.             }
  223.         } else {
  224.             bp_log ("     Static address assigned: %s\n", 
  225.                 inet_ntoa (hp->iaddr.s_addr));
  226.             put32 ((char *) &(rp->yiaddr), hp->iaddr.s_addr);
  227.         }
  228.  
  229.     } else {
  230.         /* search by IP address */
  231.         bp_log ("     Resolve by IP addr %s\n", inet_ntoa (rq->ciaddr.s_addr));
  232.         for(hp = &hosts[0], n = 0 ; n < Nhosts ; n++,hp++)
  233.             if(rq->ciaddr.s_addr == hp->iaddr.s_addr)
  234.                 break;
  235.         if(n == Nhosts) {
  236.             hp = NULLHOST;
  237.             bp_log ("     Host not found, default values used.\n");
  238.         } else
  239.             bp_log ("     Lookup successful.\n");
  240.         put32 ((char *) &(rp->ciaddr), rq->ciaddr.s_addr);
  241.     }
  242.  
  243.     put32 ((char *) &(rp->siaddr), iface->addr);
  244.  
  245.     /* Determine the bootp file */
  246.     file[0] = 0;
  247.     if(rq->file[0] == 0) {         /* if client didn't specify file */
  248.         /* Use the host record file, else the default file */
  249.         if((hp == NULLHOST) || (hp->bootfile[0] == 0))
  250.             strcpy(file, defaultboot);
  251.         else
  252.             strcpy(file, hp->bootfile);
  253.     } else {
  254.         /* use client specified file */
  255.         strcpy(file, rq->file);
  256.     }
  257.  
  258.     /* If a file is specified, specify the path to the bootp file */
  259.     path[0] = 0;
  260.     if((*homedir != 0) && (*file != 0)) {
  261.         strcpy(path, homedir);
  262.         strcat(path, "/");
  263.     }
  264.  
  265.     if(file[0] == '/')     /* if absolute pathname */
  266.         strcpy(path, file);
  267.     else
  268.         strcat(path, file);
  269.  
  270.     /* No files are provided here, just return a path. */
  271.     strcpy(rp->file, path);
  272.  
  273.     /* Fill in the vendor information */
  274.     vend_fill (rp->vend, iface, hp);
  275.  
  276.     sendreply (rp, iface);
  277.     free (rp); 
  278.  
  279. };
  280.  
  281.  
  282. /* Print the bootp structure. */
  283. void
  284. bootp_print_packet  (bp)
  285. struct bootp *bp;
  286. {
  287.     bp_log ("Packet op code........................%d\n", bp->op);
  288.     bp_log ("hardware address type.................%d\n", bp->htype);
  289.     bp_log ("hardware address length...............%d\n", bp->hlen);
  290.     bp_log ("client sets to zero...................%d\n", bp->hops);
  291.     bp_log ("transaction ID........................%ld\n", bp->xid);
  292.     bp_log ("seconds elapsed since client booted...%d\n", bp->secs);
  293.     bp_log ("unused................................%d\n", bp->unused);
  294.     bp_log ("Client IP address, if known...........%s\n",
  295.             inet_ntoa ((int32)bp->ciaddr.s_addr));
  296.     bp_log ("Server supplied IP address............%s\n", 
  297.             inet_ntoa ((int32)bp->yiaddr.s_addr));
  298.     bp_log ("Server IP address.....................%s\n", 
  299.             inet_ntoa ((int32)bp->siaddr.s_addr));
  300.     bp_log ("Gateway IP address....................%s\n", 
  301.             inet_ntoa ((int32)bp->giaddr.s_addr));
  302.     bp_log ("Client hardware address...............%x:%x:%x:%x:%x:%x\n",
  303.         bp->chaddr[0], bp->chaddr[1], bp->chaddr[2],
  304.         bp->chaddr[3], bp->chaddr[4], bp->chaddr[5]);
  305.     bp_log ("Server host name......................'%s'\n", bp->sname);
  306.     bp_log ("Boot file name........................'%s'\n", bp->file);
  307.     
  308.     vend_print (bp->vend);    
  309. }
  310.  
  311.  
  312.  
  313. static void
  314. vend_print (vend)
  315. char *vend; 
  316. {
  317.     unsigned char ch;
  318.     int size;
  319.     char *start;
  320.     int32 *ipaddr;
  321.     int i;
  322.  
  323.     start = vend;
  324.  
  325.     bp_log ("Magic Cookie..........................x%02x%02x%02x%02x\n", 
  326.         (int) vend[0], (int) vend[1], (int) vend[2], (int) vend[3]);
  327.     vend = vend + 4;
  328.  
  329.     while(((ch = *vend++) != BOOTP_END) && (vend - start <= 64)) 
  330.         switch(ch) {
  331.  
  332.         case BOOTP_PAD:     /* They're just padding */
  333.             continue;
  334.         case BOOTP_SUBNET:      /* fixed length, 4 octets */
  335.             size = (int) *vend++;
  336.             ipaddr = (int32 *) vend;
  337.             bp_log ("Vend Subnet...........................%s\n", inet_ntoa
  338. (*ipaddr));
  339.             vend += size;
  340.             break;
  341.         case BOOTP_HOSTNAME:
  342.             size = (int) *vend++;
  343.             bp_log ("Vend Hostname.........................%s\n", vend);
  344.             vend += size;
  345.             break;
  346.         case BOOTP_DNS:
  347.             size = (int) *vend++;
  348.             for(i = 0; i < (size / 4); i++) {
  349.                 ipaddr = (int32 *) vend;
  350.                 bp_log ("Vend DomainNS.........................%s\n", 
  351.                     inet_ntoa (*ipaddr));
  352.                 vend += 4;
  353.             }
  354.             break;
  355.         case BOOTP_GATEWAY:
  356.             size = (int) *vend++;
  357.             for(i = 0; i < (size / 4); i++) {
  358.                 ipaddr = (int32 *) vend;
  359.                 bp_log ("Vend Gateway..........................%s\n", 
  360.                     inet_ntoa (*ipaddr));
  361.                 vend += 4;
  362.             }
  363.             break;
  364.             
  365.             
  366.         default:        /* variable field we don't know about */
  367.             size = *vend++;
  368.             vend += size;
  369.             break;
  370.     }
  371.  
  372. }
  373.  
  374.  
  375.  
  376. static void
  377. vend_fill (vend, iface, hp)
  378. char *vend;
  379. struct iface *iface;
  380. struct host *hp;
  381. {
  382.     char     cookie[5] = {99, 130, 83, 99, 0};
  383.     int     len;
  384.     int    mod;
  385.     int    i;
  386.     char    *sizep;
  387.  
  388.     /* Magic cookie */
  389.     strcpy (vend, cookie); 
  390.     vend += 4;
  391.  
  392.     /* Send the iface subnet */
  393.     /* Pad so number falls on word boundry */
  394.     
  395.     vend++;
  396.     vend++;
  397.  
  398.     *vend = BOOTP_SUBNET;
  399.     vend++;
  400.     *vend = 4;
  401.     vend++;
  402.     put32 (vend, iface->netmask);
  403.     vend += 4;
  404.  
  405.     
  406.     /* Send the DNS */
  407.     if(bp_DefaultDomainNS[0] != 0) {
  408.         /* Pad for allignment */
  409.         vend++;
  410.         vend++;
  411.  
  412.         *vend = BOOTP_DNS;
  413.         vend++;
  414.         sizep = vend;
  415.         vend++;
  416.         for(i = 0; (i < BP_MAXDNS) && (bp_DefaultDomainNS[i] != 0); i++) {
  417.             put32 (vend, bp_DefaultDomainNS[i]);
  418.             *sizep = *sizep + 4;
  419.             vend += 4;
  420.         }
  421.     }
  422.  
  423.     /* Send the default gateway */
  424.     if(R_default.iface == iface) {
  425.         vend++;
  426.         vend++;
  427.  
  428.         *vend = BOOTP_GATEWAY; 
  429.         vend++;    
  430.         *vend = 4;    
  431.         vend++;
  432.         put32 (vend, R_default.gateway);
  433.         vend +=  4;
  434.     }
  435.     
  436.     /* Send the hostname */
  437.     if(hp != NULLHOST) {
  438.         /* Pad so name begins on a word boundry */
  439.         vend++;
  440.         vend++;
  441.  
  442.         *vend = BOOTP_HOSTNAME;
  443.         vend++;
  444.         *vend = len = strlen (hp->name) + 1;
  445.         vend++;
  446.         strcpy (vend, hp->name);
  447.         vend += len;
  448.  
  449.         /* Pad to a word. */
  450.         mod = 4 - (len % 4);
  451.         for(i = 0; i < mod; i++) {
  452.             *vend = BOOTP_PAD;
  453.             vend++;
  454.         }
  455.     }
  456.  
  457.     /* Mark the end of the data */
  458.     *vend = BOOTP_END;
  459. }
  460.  
  461.  
  462.  
  463. /*
  464.  * Send a reply packet to the client.  'forward' flag is set if we are
  465.  * not the originator of this reply packet.
  466.  */
  467. static void
  468. sendreply(bp, iface)
  469. struct bootp *bp;
  470. struct iface *iface;
  471. {
  472.     struct mbuf *buf;
  473.     int32 faddr;
  474.     int16 length;
  475.     char *cp;
  476.  
  477.     /*
  478.      * If the client IP address is specified, use that
  479.      * else if gateway IP address is specified, use that
  480.      * else make a temporary arp cache entry for the client's NEW 
  481.      * IP/hardware address and use that.
  482.      */
  483.     if(bp->ciaddr.s_addr) {
  484.         faddr = get32 ((char *) &(bp->ciaddr));
  485.     } else {
  486.         faddr = get32 ((char *) &(bp->yiaddr));
  487.         arp_add (faddr, (int16) bp->htype, bp->chaddr, 0);
  488.     }
  489.  
  490.     if((buf = qdata ((char *)bp, sizeof (struct bootp))) == NULLBUF)
  491.         return;
  492.     if((buf = pushdown (buf, UDPHDR)) == NULLBUF)
  493.         return;
  494.  
  495.     length = sizeof (struct bootp) + UDPHDR;
  496.  
  497.     cp = buf->data;
  498.     cp = put16 (cp, IPPORT_BOOTPS);        /* Source */
  499.     cp = put16 (cp, IPPORT_BOOTPC);        /* Dest */
  500.     cp = put16 (cp, length);
  501.     *cp++ = 0;
  502.     *cp = 0;
  503.  
  504.     ip_send (iface->addr, faddr, UDP_PTCL, 0, 0, buf, length, 0, 0);
  505. };
  506.  
  507.  
  508.  
  509.  
  510.  
  511.